module spi_send_n
#(
    parameter   INIT_DELAY  = 'd30,
    parameter   SPI_DELAY   = 'd4,
    parameter   DELAY_NUM   = 'd20,
    parameter   DELAY1 = 'd6000,
    parameter   DELAY2 = 'd10000
)
(
    input   wire       sys_clk,     
    input   wire       low_clk,     
    input   wire       sys_rst_n,    

    input   wire       miso,
    output  wire       cs1,
    output  wire       sck,
    output  wire       mosi,
    output  wire       spi_rst
);

parameter   SPI_LEN   =   24;

reg [15:0] cnt;
reg cnt_flag;
reg cnt_flag_q;

wire sys_valid;

//SPI
reg i_TX_DV;           

wire o_TX_Ready;       
wire o_RX_DV;          
wire [7:0] o_RX_Byte;  
reg  [7:0] i_TX_Byte;  

reg cs_reg1;

reg [2:0] cs_cnt;

assign cs1 = cs_reg1;
assign spi_rst = sys_rst_n;

//ram
wire [7:0]  rd_data;   
reg  [6:0]  rd_addr;   
reg  rd_en;            

reg  [7:0]  wr_data;   
reg  [6:0]  wr_addr;   
reg  wr_en;            

//ram 
reg par_rd_en;        
reg par_rd_en_q;        

//两段式状态机
reg  [6:0]   cur_st;    
reg  [6:0]   nxt_st;   

//
reg miso_q;
reg miso_q1;
wire miso_neg;


always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        cur_st <= 0;
    else 
        cur_st <= nxt_st;
end

always @(*) begin 
    if ((cur_st > 11) & (cur_st < SPI_LEN)) begin
        if(cur_st[0] == 1'b0) begin
            if (sys_valid) begin 
                nxt_st = cur_st + 1;
            end
            else begin
                nxt_st = cur_st;
            end
        end
        else if(cur_st[0] == 1'b1) begin
            if (o_RX_DV & (cs_cnt == 3)) begin 
                nxt_st = cur_st + 1;
            end
            else begin
                nxt_st = cur_st;
            end
        end
    end 
    else if(cur_st == SPI_LEN) begin
        if (sys_valid) begin 
            nxt_st = SPI_LEN + 1;
        end
        else begin
            nxt_st = cur_st;
        end
    end
    else begin
        case(cur_st) 
            0: begin
                if (sys_valid) begin 
                    nxt_st = 1;
                end
                else begin
                    nxt_st = cur_st;
                end
            end
            1,3,5,7,9,11: begin
                if (o_RX_DV & (cs_cnt == 3)) begin 
                    nxt_st = cur_st + 1;
                end
                else begin
                    nxt_st = cur_st;
                end
            end
            2,4,6,8,10: begin
                if (sys_valid) begin 
                    nxt_st = cur_st + 1;
                end
                else begin
                    nxt_st = cur_st;
                end
            end
            default:
                nxt_st = cur_st;
        endcase
    end 
end

always @(posedge low_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin
        cnt <= INIT_DELAY;
    end
    else if(cnt_flag & (cur_st[0] == 1'b1) & (cs_cnt < 3)) begin  
        cnt <= SPI_DELAY;
    end
    else if(cnt_flag & ((cur_st > 0)&&(cur_st == 12))) begin  
        cnt <= DELAY1;
    end
    else if(cnt_flag & ((cur_st > 0)&&(cur_st == SPI_LEN))) begin  
        cnt <= DELAY2;
    end
    else if(cnt_flag & ((cur_st > 0)&&(cur_st < SPI_LEN)&&(cur_st[0] == 1'b0))) begin  
        cnt <= DELAY_NUM;
    end
    else if(cnt > 0) begin
        cnt <= cnt - 1;
    end
end

    // else if(miso_neg & (rd_addr == 37)) begin
    //     par_rd_en <= 1'b1;
    // end

//用于同步低频时钟的信号
always @(posedge low_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin
        cnt_flag <= 1'b0;
    end
    else if(cnt == 0) begin
        cnt_flag <= 1'b1;
    end
    else begin
        cnt_flag <= 1'b0;
    end
end

always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin
        cnt_flag_q <= 1'b0;
    end
    else begin
        cnt_flag_q <= cnt_flag;
    end
end

assign sys_valid = ~cnt_flag_q & cnt_flag;
///////////////////////////////////////////////////////////////


//SPI CS
always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin
        cs_cnt <= 'd0;
    end
    else if(sys_valid & (cur_st[0] == 1'b1)) begin
        cs_cnt <= cs_cnt + 1;
    end
    else if(sys_valid & ((cur_st > 0) && (cur_st[0] == 1'b0))) begin
        cs_cnt <= 'd0;
    end
end

always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin
        cs_reg1 <= 1'b1;
    end
    else begin
        cs_reg1 <= 1'b0;
    end
end

//RAM Read
always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin
        rd_en <= 1'b0;
    end
    else if(sys_valid & (cur_st[0] == 1'b1)) begin
        rd_en <= 1'b1;
    end
    else begin
        rd_en <= 1'b0;
    end
end

always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin
        rd_addr <= 'd0;
    end
    else if(rd_en & (rd_addr < 37)) begin
        rd_addr <= rd_addr + 1;
    end 
end

always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin
        i_TX_DV <= 1'b0;
    end 
    else begin
        i_TX_DV <= par_rd_en_q;
    end      
end

always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin
        miso_q <= 'd0;
        miso_q1 <= 'd0;
    end 
    else begin
        miso_q <= miso;
        miso_q1 <= miso_q;
    end      
end

assign miso_neg = miso_q1 & ~miso_q;

reg o_TX_Ready_q;
reg o_TX_Ready_q1;
wire o_TX_Ready_pos;
assign o_TX_Ready_pos = ~o_TX_Ready_q1 & o_TX_Ready_q;

always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin
        o_TX_Ready_q <= 'd0;
        o_TX_Ready_q1 <= 'd0;
    end 
    else begin
        o_TX_Ready_q <= o_TX_Ready;
        o_TX_Ready_q1 <= o_TX_Ready_q;
    end      
end

reg [2:0]rd_cnt;
always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin
        rd_cnt <= 'd3;
    end 
    else if(o_TX_Ready_pos & (rd_addr == 37) & (rd_cnt < 3)) begin     
        rd_cnt <= rd_cnt + 1;
    end     
    else if(par_rd_en & (rd_addr == 37) & (rd_cnt == 3)) begin     
        rd_cnt <= 'd0;
    end 
end

// param读取通过SPI发送
always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin
        par_rd_en <= 1'b0;
    end
    else if(rd_en & (rd_addr < 36)) begin
        par_rd_en <= 1'b1;
    end
    else if(miso_neg & (rd_addr == 37) & (rd_cnt == 3)) begin
        par_rd_en <= 1'b1;
    end
    else if(o_TX_Ready_pos & (rd_addr == 37) & (rd_cnt < 2)) begin
        par_rd_en <= 1'b1;
    end
    else begin
        par_rd_en <= 1'b0;
    end
end

always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin
        par_rd_en_q <= 1'b0;
    end
    else begin
        par_rd_en_q <= par_rd_en;
    end
end

always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin
        i_TX_Byte <= 'd0;
    end
    else if(par_rd_en_q) begin
        case(rd_addr)
            37: begin
                i_TX_Byte <= 'h00;
            end
            default: begin
                i_TX_Byte <= rd_data;
            end
        endcase    
    end
end

///////////////////////////////////////////////////////////////////////////////////////

spi_ram
spi_ram_inst( 
	.dia  (wr_data), 
    .addra(wr_addr), 
    .cea  (wr_en  ), 
    .clka (sys_clk),

	.dob  (rd_data), 
    .addrb(rd_addr), 
    .ceb  (rd_en  ), 
    .clkb (sys_clk)
);

SPI_Master 
#(
    .SPI_MODE(3),
    .CLKS_PER_HALF_BIT(2)
)
spi_master_inst
(
    // Control/Data Signals,
    .i_Rst_L(sys_rst_n),       // FPGA Reset
    .i_Clk(sys_clk),           // FPGA Clock

    // TX (MOSI) Signals
    .i_TX_Byte(i_TX_Byte),     // Byte to transmit on MOSI
    .i_TX_DV(i_TX_DV),         // Data Valid Pulse with i_TX_Byte
    .o_TX_Ready(o_TX_Ready),   // Transmit Ready for next byte

    // RX (MISO) Signals
    .o_RX_DV(o_RX_DV),         // Data Valid pulse (1 clock cycle)
    .o_RX_Byte(o_RX_Byte),     // Byte received on MISO

    // SPI Interface
    .o_SPI_Clk(sck),
    .i_SPI_MISO(miso),
    .o_SPI_MOSI(mosi)
);



endmodule

